﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PeriodicalTaskDemo.Tasks
{
    /// <summary>
    /// 日志内容，包括级别、类型、位置、行号、内容等。
    /// </summary>
    public class XLog
    {
        /// <summary>
        /// 日志时间，创建时取当前系统时间。
        /// </summary>
        public DateTime LogTime = DateTime.Now;

        /// <summary>
        /// 1、日志的类型。
        /// </summary>
        public XLogLevel LogLevel = 0;

        /// <summary>
        /// 2、代码所在的类名。
        /// </summary>
        public string ClassName = string.Empty;

        /// <summary>
        /// 3、代码所在的方法名。
        /// </summary>
        public string MethodName = string.Empty;

        /// <summary>
        /// 4、代码所在的行号。
        /// </summary>
        public int LineNumber = -1;

        /// <summary>
        /// 5、代码所在文件的全路径，保留，暂时未启动。
        /// </summary>
        public string Filepath = string.Empty;

        /// <summary>
        /// 6、日志内容
        /// </summary>
        public string LogContent = string.Empty;



        public XLog() { }

        /// <summary>
        /// 初始化日志，包括函数名，方法名，行号，文件名等信息。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <param name="logLevel">日志类型。</param>
        /// <param name="traceLevel">追踪等级，默认为1。每额外封装一层则加1。</param>
        public XLog(string content, XLogLevel logLevel = XLogLevel.INFO, int traceLevel = 1)
        {
            StackFrame st = new StackTrace(traceLevel, true).GetFrame(0);
            LogLevel = logLevel;
            Filepath = st?.GetFileName() ?? "";
            ClassName = st?.GetMethod()?.DeclaringType?.FullName ?? "";
            MethodName = st?.GetMethod()?.Name ?? "";
            LineNumber = st?.GetFileLineNumber() ?? 0;
            LogContent = content;
        }

        /// <summary>
        /// 格式为 2022/06/15 10:09:46 2 Hao.Utils.HWLog::Log@114 -> hello2
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var path = $"{ClassName}.{MethodName}@L{LineNumber}";
            return $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}\t{path}\t{LogLevel}\t{LogContent}";
        }

        public void Log1(string content, XLogLevel logLevel = XLogLevel.INFO)
        {
            // public HWLog(string content, HWLogLevel logLevel = HWLogLevel.INFO, int traceLevel = 1)
            StackFrame st = new StackTrace(1, true).GetFrame(0);
            LogLevel = logLevel;
            Filepath = st?.GetFileName() ?? "";
            ClassName = st?.GetMethod()?.DeclaringType?.FullName ?? "";
            MethodName = st?.GetMethod()?.Name ?? "";
            LineNumber = st?.GetFileLineNumber() ?? -1;
            LogContent = content;
        }

        /// <summary>
        /// 将原始字符串转换为带有引号的字符串，同时对引号进行转义。
        /// </summary>
        /// <returns></returns>
        public string ToCsvString()
        {
            string[] values = new string[7];
            values[0] = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
            values[1] = LogLevel.ToString();
            values[2] = Filepath;
            values[3] = LineNumber.ToString();
            values[4] = ClassName;
            values[5] = MethodName;
            values[6] = LogContent;

            string quote = "\"";
            for (int i = 0; i < values.Length; i++)
                if (values[i].Contains(quote) || values[i].Contains(",") || values[i].Contains("\r") || values[i].Contains("\n"))
                    values[i] = quote + values[i].ToString().Replace(quote, quote + quote) + quote;


            return string.Join(",", values);
        }

    }


    /// <summary>
    /// 日志类型根据重要程度由高到底分为 FATAL, ERROR, WARN, INFO, DEBUG 5种。
    /// 为了便于操作，还设置了 OFF 和 ALL 两种表示全半或全开。
    /// </summary>
    public enum XLogLevel
    {
        /// <summary>
        /// 关闭所有日志。
        /// </summary>
        OFF = 0,

        /// <summary>
        /// 调试用信息。
        /// </summary>
        DEBUG = 1,

        /// <summary>
        /// 一般系统信息，如果打开时间，操作日志等。
        /// </summary>
        INFO = 2,

        /// <summary>
        /// 一些可能的错误，哪数值异常，没有保存就关闭等。
        /// </summary>
        WARNNING = 4,

        /// <summary>
        /// 一般非功能性的错误，如数据格式不正确，连接失败，文件不存在等。
        /// </summary>
        ERROR = 8,

        /// <summary>
        /// 系统崩溃级错误，在系统出现重大错误时由 try-catch 捕捉。
        /// </summary>
        FATAL = 16,

        /// <summary>
        /// 打开所有类型开关，目前只有FATAL, ERROR, WARN, INFO 和 DEBUG 五类。
        /// </summary>
        ALL = 31
    }

}
